package gui;

import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.FlowLayout;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.GridLayout;
import java.awt.Insets;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.ItemEvent;
import java.awt.event.ItemListener;
import java.lang.reflect.Constructor;
import java.util.Random;
import java.util.Vector;

import javax.swing.BorderFactory;
import javax.swing.ImageIcon;
import javax.swing.JButton;
import javax.swing.JComboBox;
import javax.swing.JLabel;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JSpinner;
import javax.swing.border.Border;
import javax.swing.border.CompoundBorder;
import javax.swing.border.EmptyBorder;
import javax.swing.border.TitledBorder;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;
import javax.swing.plaf.ColorUIResource;

import core.AbstractAgent;
import core.Environment;
import core.Environment.Type;
import core.Square;

public class SettingsPanel extends JPanel {

	private static final long serialVersionUID = 1L;

	public MainJFrame mainFrame;

	private JPanel dimensionPanel;

	private JPanel agentPanel;
	private JSpinner renataTimeField;
	private JLabel renataTimelabel;
	private JSpinner kStepsField;
	private JLabel refreshTimeLabel;
	private JSpinner refreshTimeField;

	private JPanel commandPanel;
	private JButton refreshButton;
	JButton controlButton;

	private JPanel statusPanel;
	private JLabel pmLabel;
	private JLabel pmValueLabel;
	private JLabel stepsLabel;
	private JLabel stepsValueLabel;
	private JLabel currTimeLabel;
	private JLabel currTimeValueLabel;
	private JLabel kStepsLabel;
	private JLabel kStepsValueLabel;

	private JComboBox envTypeCombobox;

	ImageIcon playIcon, stopIcon, nextIcon;

	private JButton onesButton;
	private JLabel currTypeEnvLabel;
	private JLabel currTypeEnvValueLabel;

	private JButton resetButton;

	private JLabel goalReachedLabel;

	/**
	 * 
	 * @param mainFrame
	 */
	public SettingsPanel(final MainJFrame mainFrame) {
		{
			this.mainFrame = mainFrame;

			playIcon = ImageLoader.playIcon;
			stopIcon = ImageLoader.stopIcon;
			nextIcon = ImageLoader.nextIcon;

			GridBagLayout jPanel2Layout = new GridBagLayout();
			jPanel2Layout.rowWeights = new double[] { 0.1, 0.1, 0.1, 0.1 };
			jPanel2Layout.rowHeights = new int[] { 1, 1, 1, 1 };
			jPanel2Layout.columnWeights = new double[] { 0.1 };
			jPanel2Layout.columnWidths = new int[] { 1 };

			setLayout(jPanel2Layout);
			{
				dimensionPanel = new JPanel();
				dimensionPanel.setPreferredSize(new Dimension(320, 100));
				Border marginOutside = new EmptyBorder(10, 10, 10, 10);
				TitledBorder title = BorderFactory
						.createTitledBorder("Environment Type");
				CompoundBorder upperBorder = new CompoundBorder(marginOutside,
						title);
				Border marginInside = new EmptyBorder(10, 15, 10, 15);
				dimensionPanel.setBorder(new CompoundBorder(upperBorder,
						marginInside));

				/* input field to set the size of the floor */
				add(dimensionPanel, new GridBagConstraints(0, 0, 1, 1, 0.0,
						0.0, GridBagConstraints.CENTER,
						GridBagConstraints.NONE, new Insets(0, 0, 0, 0), 0, 0));

				Vector<Environment.Type> envTypeVector = new Vector<Environment.Type>();
				envTypeVector.add(Environment.Type.DYNAMIC1);
				envTypeVector.add(Environment.Type.DYNAMIC2);
				envTypeVector.add(Environment.Type.DYNAMIC3);
				envTypeVector.add(Environment.Type.STATIC);
				envTypeCombobox = new JComboBox(envTypeVector);
				envTypeCombobox.setSelectedItem(mainFrame.env.type);
				envTypeCombobox.addItemListener(new ItemListener() {

					@Override
					public void itemStateChanged(ItemEvent arg0) {
						SettingsPanel.this.mainFrame.env.type = (Type) SettingsPanel.this.envTypeCombobox
								.getSelectedItem();
						SettingsPanel.this.mainFrame.env.k_steps = (Integer) SettingsPanel.this.kStepsField
								.getValue();
						SettingsPanel.this.mainFrame.env.steps_count = (Integer) SettingsPanel.this.kStepsField
								.getValue();
						SettingsPanel.this.mainFrame.ciccioPasticcio.max_steps_per_goal = (Integer) SettingsPanel.this.kStepsField
								.getValue();
						update();
					}
				});

				dimensionPanel.add(envTypeCombobox);
				
				
				{
					/* Refresh current configuration */
					refreshButton = new JButton();
//					generationPanel.add(refreshButton);
					dimensionPanel.add(refreshButton);
					refreshButton.setText("Generate");
					refreshButton.addActionListener(new ActionListener() {
						@Override
						public void actionPerformed(ActionEvent arg0) {
							refreshButton.setBackground(new ColorUIResource(
									238, 238, 238));
							mainFrame.env.floor.generateObject();
							Random random = new Random();
							int room = Math.abs(random.nextInt()) % 4;
							int cell = Math.abs(random.nextInt()) % 8;
							while (mainFrame.env.floor.rooms[room].squares[cell].type != Square.Type.Clean) {
								room = Math.abs(random.nextInt()) % 4;
								cell = Math.abs(random.nextInt()) % 8;
							}
							mainFrame.ciccioPasticcio.x = room;
							mainFrame.ciccioPasticcio.y = cell;
							mainFrame.getContentPane().remove(
									mainFrame.gridPanel);
							mainFrame.gridPanel = new GridPanel(mainFrame.env);
							mainFrame.getContentPane().add(mainFrame.gridPanel,
									BorderLayout.EAST);
							mainFrame.pack();
						}
					});
				}
				
				
			}
			{
				agentPanel = new JPanel();
				add(agentPanel, new GridBagConstraints(0, 1, 1, 1, 0.0, 0.0,
						GridBagConstraints.CENTER, GridBagConstraints.NONE,
						new Insets(0, 0, 0, 0), 0, 0));
				Border marginOutside = new EmptyBorder(10, 10, 10, 10);
				TitledBorder title = BorderFactory
						.createTitledBorder("Agent's settings");
				CompoundBorder upperBorder = new CompoundBorder(marginOutside,
						title);
				Border marginInside = new EmptyBorder(10, 10, 10, 10);
				agentPanel.setBorder(new CompoundBorder(upperBorder,
						marginInside));

				agentPanel.setLayout(new GridLayout(3, 1));

				JPanel renataTimePanel = new JPanel();
				renataTimePanel.setLayout(new FlowLayout());
				agentPanel.add(renataTimePanel);

				renataTimelabel = new JLabel("Time to Renata");
				renataTimePanel.add(renataTimelabel);
				renataTimeField = new JSpinner();
				renataTimeField
						.setValue(mainFrame.ciccioPasticcio.renata_time);
				renataTimeField.setPreferredSize(new Dimension(60, 30));
				renataTimeField.addChangeListener(new ChangeListener() {

					@Override
					public void stateChanged(ChangeEvent arg0) {
						mainFrame.ciccioPasticcio.actionList.clear();
						
						int timeToEnergy = (Integer) SettingsPanel.this.renataTimeField
								.getValue();
						if (timeToEnergy < 0) {
							timeToEnergy = 0;
							SettingsPanel.this.renataTimeField.setValue(0);
						}
						mainFrame.env.k_steps = timeToEnergy;
						mainFrame.ciccioPasticcio.renata_time = timeToEnergy;
						update();
					}
				});
				renataTimePanel.add(renataTimeField);
				// //////////
				JPanel kStepsPanel = new JPanel();
				kStepsPanel.setLayout(new FlowLayout());
				agentPanel.add(kStepsPanel);

				kStepsLabel = new JLabel("K Stepssss");
				kStepsPanel.add(kStepsLabel);
				kStepsField = new JSpinner();
				kStepsField.setValue(mainFrame.env.steps_count);
				kStepsField.setPreferredSize(new Dimension(60, 30));
				kStepsField.addChangeListener(new ChangeListener() {
					// TODO
					@Override
					public void stateChanged(ChangeEvent arg0) {
						int steps = (Integer) SettingsPanel.this.kStepsField
								.getValue();
						if (steps < 2) {
							steps = 2;
							SettingsPanel.this.kStepsField.setValue(2);
						}
						mainFrame.env.steps_count = steps;
						update();
					}
				});

				kStepsPanel.add(kStepsField);
				// //////////////

				JPanel refreshTimePanel = new JPanel();
				refreshTimePanel.setLayout(new FlowLayout());
				agentPanel.add(refreshTimePanel);

				refreshTimeLabel = new JLabel("Refresh Time");
				refreshTimePanel.add(refreshTimeLabel);
				refreshTimeField = new JSpinner();
				refreshTimeField
						.setValue(GridPanel.refresh_time);
				refreshTimeField.setPreferredSize(new Dimension(60, 30));
				refreshTimeField.addChangeListener(new ChangeListener() {
					// TODO
					@Override
					public void stateChanged(ChangeEvent arg0) {
						int refresh_time = (Integer) SettingsPanel.this.refreshTimeField
								.getValue();
						if (refresh_time < 50) {
							refresh_time = 50;
							SettingsPanel.this.refreshTimeField.setValue(50);
						}
						GridPanel.refresh_time = refresh_time;
						update();
					}
				});

				refreshTimePanel.add(refreshTimeField);

				// ///////
				kStepsField.addChangeListener(new ChangeListener() {

					@Override
					public void stateChanged(ChangeEvent arg0) {
						mainFrame.ciccioPasticcio.actionList.clear();
						int ksteps = (Integer) SettingsPanel.this.kStepsField
								.getValue();
						if (ksteps < -1) {
							ksteps = -1;
							SettingsPanel.this.kStepsField.setValue(-1);
						}
						mainFrame.env.type = (Environment.Type) SettingsPanel.this.envTypeCombobox
								.getSelectedItem();
						mainFrame.ciccioPasticcio.max_steps_per_goal = ksteps;
						mainFrame.env.k_steps = ksteps;
						mainFrame.env.steps_count = ksteps;
						update();
					}
				});
				// renataTimePanel.add(KStepsField);

				JPanel agentVisibilityPanel = new JPanel();

				agentVisibilityPanel.setLayout(new FlowLayout());
			}
			{
				commandPanel = new JPanel();
				commandPanel.setPreferredSize(new Dimension(300, 110));
				Border marginOutside = new EmptyBorder(10, 10, 10, 10);
				TitledBorder title = BorderFactory
						.createTitledBorder("Commands");
				CompoundBorder upperBorder = new CompoundBorder(marginOutside,
						title);
				Border marginInside = new EmptyBorder(10, 10, 10, 10);
				commandPanel.setBorder(new CompoundBorder(upperBorder,
						marginInside));

				add(commandPanel, new GridBagConstraints(0, 2, 1, 1, 0.0, 0.0,
						GridBagConstraints.CENTER, GridBagConstraints.NONE,
						new Insets(0, 0, 0, 0), 0, 0));
				{
					/* Start simulation of agent */
					resetButton = new JButton();
					commandPanel.add(resetButton);
					resetButton.setText("Reset");
					resetButton.addActionListener(new ActionListener() {
						@Override
						public void actionPerformed(ActionEvent arg0) {
							@SuppressWarnings("rawtypes")
							Class[] argsConstructor = new Class[] { int.class,
									int.class, int.class };
							Integer x = new Integer(0);
							Integer y = new Integer(0);
							Integer Time = new Integer(
									(Integer) SettingsPanel.this.renataTimeField
											.getValue());
							Object[] intArgs = new Object[] { x, y, Time };
							try {
								@SuppressWarnings("rawtypes")
								Constructor constructor = mainFrame.ciccioPasticcio
										.getClass().getConstructor(
												argsConstructor);
								mainFrame.ciccioPasticcio = (AbstractAgent) constructor
										.newInstance(intArgs);
							} catch (Exception e) {
								e.printStackTrace();
							}

							mainFrame.env.agent = mainFrame.ciccioPasticcio;
							mainFrame.env.type = Environment.Type.STATIC;

							mainFrame.gridPanel.update();
							mainFrame.settingsPanel.envTypeCombobox
									.setSelectedIndex(3);
							mainFrame.settingsPanel.renataTimeField
									.setValue(100);
							mainFrame.settingsPanel.update();
							mainFrame.pack();
						}
					});
					/* Start simulation of agent */
					controlButton = new JButton();
					commandPanel.add(controlButton);
					controlButton.setIcon(playIcon);
					controlButton.addActionListener(new ActionListener() {
						@Override
						public void actionPerformed(ActionEvent arg0) {
							if ((Integer) SettingsPanel.this.renataTimeField
									.getValue() <= 0) {
								JOptionPane
										.showMessageDialog(null,
												"Non � possibile che il tempo sia minore o uguale a 0!");
								return;
							}
							if ((Integer) SettingsPanel.this.kStepsField
									.getValue() <= 0
									&& (Environment.Type) SettingsPanel.this.envTypeCombobox
											.getSelectedItem() != Environment.Type.STATIC) {
								JOptionPane
										.showMessageDialog(
												null,
												"Il valore di K Steps non pu� essere minore o uguale a 0 con un ambiente non statico!");
								return;
							}
							System.out.println("Clicked " + mainFrame.stopped);
							if (mainFrame.stopped) {
								mainFrame.stopped = false;
								System.out.println("Start thread");
								class myThread implements Runnable {
									public void run() {
										mainFrame.mainLoop();
									}
								}
								new Thread(new myThread()).start();
							} else {
								mainFrame.stopped = true;
								mainFrame.env.agent.x = 0;
								mainFrame.env.agent.y = 0;
								mainFrame.gridPanel.update();
							}
							update();
						}
					});
					/* Start simulation of agent */
					onesButton = new JButton();
					commandPanel.add(onesButton);
					onesButton.setIcon(nextIcon);
					onesButton.addActionListener(new ActionListener() {
						@Override
						public void actionPerformed(ActionEvent arg0) {
							class myThread implements Runnable {
								public void run() {
									mainFrame.mainLoopOnes();
								}
							}
							new Thread(new myThread()).start();
						}
					});
				}

			}
			{
				statusPanel = new JPanel();
				Border marginOutside = new EmptyBorder(10, 10, 10, 10);
				TitledBorder title = BorderFactory.createTitledBorder("Status");
				CompoundBorder upperBorder = new CompoundBorder(marginOutside,
						title);
				Border marginInside = new EmptyBorder(10, 10, 10, 10);
				statusPanel.setBorder(new CompoundBorder(upperBorder,
						marginInside));
				statusPanel.setLayout(new GridLayout(6, 1));
				add(statusPanel, new GridBagConstraints(0, 3, 1, 1, 0.0, 0.0,
						GridBagConstraints.CENTER, GridBagConstraints.NONE,
						new Insets(0, 0, 0, 0), 0, 0));

				JPanel pmPanel = new JPanel();
				JPanel currTypeEnvPanel = new JPanel();
				statusPanel.add(currTypeEnvPanel);
				{
					currTypeEnvLabel = new JLabel("Environment's type:");
					currTypeEnvValueLabel = new JLabel("" + mainFrame.env.type);
					currTypeEnvPanel.add(currTypeEnvLabel);
					currTypeEnvPanel.add(currTypeEnvValueLabel);
				}
				statusPanel.add(pmPanel);
				{
					pmLabel = new JLabel("Performance Measure:");
					pmValueLabel = new JLabel(""
							+ mainFrame.env.performanceMeasure());
					pmPanel.add(pmLabel);
					pmPanel.add(pmValueLabel);
				}
				JPanel stepPanel = new JPanel();
				statusPanel.add(stepPanel);
				{
					stepsLabel = new JLabel("Steps Number:");
					stepsValueLabel = new JLabel(""
							+ mainFrame.ciccioPasticcio.actionList.size());
					stepPanel.add(stepsLabel);
					stepPanel.add(stepsValueLabel);
				}
				JPanel currTimePanel = new JPanel();
				statusPanel.add(currTimePanel);
				{
					currTimeLabel = new JLabel("Agent's Time:");
					currTimeValueLabel = new JLabel(
							""
									+ (mainFrame.ciccioPasticcio.renata_time - mainFrame.ciccioPasticcio.actionList
											.size()));
					kStepsLabel = new JLabel("K Steps:");
					kStepsValueLabel = new JLabel(""
							+ mainFrame.ciccioPasticcio.max_steps_per_goal);
					currTimePanel.add(currTimeLabel);
					currTimePanel.add(currTimeValueLabel);
					currTimePanel.add(kStepsLabel);
					currTimePanel.add(kStepsValueLabel);
				}
				JPanel goalPanel = new JPanel();
				statusPanel.add(goalPanel);
				{
					goalReachedLabel = new JLabel("GOAL NOT REACHED");
					goalReachedLabel.setForeground(Color.RED);
					goalPanel.add(goalReachedLabel);
				}
			}
		}
	}

	public void update() {
		if (mainFrame.stopped)
			controlButton.setIcon(playIcon);
		else
			controlButton.setIcon(stopIcon);

		currTypeEnvValueLabel.setText("" + mainFrame.env.type);
		pmValueLabel.setText("" + mainFrame.env.performanceMeasure());
		stepsValueLabel.setText(""
				+ mainFrame.ciccioPasticcio.actionList.size());
		currTimeValueLabel.setText("" + mainFrame.ciccioPasticcio.renata_time);
		kStepsValueLabel.setText("" + mainFrame.ciccioPasticcio.max_steps_per_goal);
		if (mainFrame.ciccioPasticcio.goalReached) {
			goalReachedLabel.setForeground(Color.GREEN);
			goalReachedLabel.setText("GOAL REACHED");
		} else {
			goalReachedLabel.setForeground(Color.RED);
			goalReachedLabel.setText("GOAL NOT REACHED");
		}
	}
}
